package com.cl.code.common.utils;


import com.cl.code.common.exception.CodeLogicException;
import com.cl.code.common.model.tree.SimpleTreeItem;
import com.cl.code.common.model.tree.TreeItem;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 构造树形工具
 *
 * @author chengliang
 * @date 1.0.0
 */
public class TreeUtils {

    /**
     * 校验了死循环
     */
    public static <ID, T extends TreeItem<ID, T>> List<T> toTree(List<T> list) {
        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }
        Set<ID> idSet = new HashSet<>();
        Map<ID, List<T>> collect = list
                .stream()
                .filter(item -> item.getParentId() != null)
                .collect(Collectors.groupingBy(TreeItem::getParentId));

        List<T> tops = list
                .stream()
                .filter(item -> isTop(item.getParentId()))
                .toList();

        tops.forEach(top -> {
            idSet.add(top.getId());
            addSubNodes(top, collect, top.getId(), idSet);
        });
        return tops;
    }


    /**
     * 将树形结构转换为List
     *
     * @param list list
     * @param <T>  泛型
     * @return 结果
     */
    public static <T extends SimpleTreeItem<T>> List<T> treeToList(List<T> list) {
        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }
        List<T> result = new ArrayList<>();
        for (T item : list) {
            result.add(item);
            if (!list.isEmpty()) {
                List<T> childList = treeToList(item.getChildren());
                result.addAll(childList);
            }
        }
        return result;
    }


    private static <ID, T extends TreeItem<ID, T>> void addSubNodes(T t, Map<ID, List<T>> map, ID id, Set<ID> idSet) {
        List<T> collect;
        collect = map.remove(id);
        if (collect == null) {
            collect = Collections.emptyList();
        } else {
            Set<ID> ids = collect.stream().map(TreeItem::getId).collect(Collectors.toSet());
            HashSet<ID> longs = new HashSet<>(ids);
            longs.retainAll(idSet);
            if (!longs.isEmpty()) {
                throw new CodeLogicException("解析数据id,parentId错误导致解析时产生死循环");
            } else {
                idSet.addAll(ids);
            }
            collect.forEach(i -> addSubNodes(i, map, i.getId(), idSet));
        }
        t.setChildren(collect);
    }

    public static <ID, T extends TreeItem<ID, T>> ID findTopByChildrenId(List<T> list, ID id) {
        return findTop(treeToList(list), id);
    }

    private static <ID, T extends TreeItem<ID, T>> ID findTop(List<T> list, ID id) {
        if (list == null || list.isEmpty()) {
            throw new CodeLogicException("集合不能为空");
        }
        for (T item : list) {
            if (item.getId().equals(id)) {
                ID parentId = item.getParentId();
                if (isTop(parentId)) {
                    return item.getId();
                } else {
                    return findTop(list, parentId);
                }
            }
        }
        throw new CodeLogicException("id:" + id + "在集合中不存在");
    }

    public static <ID, T extends TreeItem<ID, T>> List<T> findChildrenByParentId(List<T> list, ID id) {
        if (list == null || list.isEmpty()) {
            throw new CodeLogicException("集合不能为空");
        }
        return findChildren(treeToList(list), id);
    }

    private static <ID, T extends TreeItem<ID, T>> List<T> findChildren(List<T> list, ID id) {
        boolean b = list.stream().anyMatch(item -> item.getId().equals(id));
        if (b) {
            for (T item : list) {
                if (item.getId().equals(id)) {
                    item.setParentId(null);
                }
            }
            List<T> tree = TreeUtils.toTree(list);
            return tree.stream().filter(item -> item.getId().equals(id)).findAny()
                    .orElseThrow(() -> new CodeLogicException("TreeUtil findChildren 代码错误"))
                    .getChildren();
        }
        throw new CodeLogicException(id + "在集合中不存在");
    }

    public static <ID, T extends TreeItem<ID, T>> List<T> findAllParentByChildren(List<T> list, ID id) {
        if (list == null || list.isEmpty()) {
            throw new CodeLogicException("集合不能为空");
        }

        List<T> result = null;

        List<T> ts = treeToList(list);
        Map<ID, T> collect = ts.stream().collect(Collectors.toMap(TreeItem::getId, Function.identity()));

        ID parentId = id;

        while (!isTop(parentId) || collect.containsKey(parentId)) {
            T t = collect.get(parentId);
            if (result == null) {
                result = new ArrayList<>();
            }
            result.add(t);
            parentId = t.getParentId();
        }

        return result;
    }

    public static <ID> boolean isTop(ID id) {
        switch (id) {
            case null -> {
                return true;
            }
            case Long l -> {
                return Objects.equals(id, -1L);
            }
            case String s -> {
                return Objects.equals(id, "-1");
            }
            default -> {
                throw new CodeLogicException("不支持的ID类型");
            }
        }
    }

}
